#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行，
# 第2行注释表示.py文件本身使用标准UTF-8编码：
print('#############定制类__str__#############')


class Student(object):
    def __init__(self, name):
        self._name = name

    def __str__(self):
        return "Student object : name %s" % self._name

    __repr__ = __str__


print(Student("wangyk"))
wangyk = Student("wangyk")
print(wangyk)
# 因为直接显示变量调用的不是__str__()，而是__repr__()，两者的区别是__str__()返回用户看到的字符串，
# 而__repr__()返回程序开发者看到的字符串，也就是说，__repr__()是为调试服务的。
print('#############定制类__iter__，使类可以迭代#############')


# 如果一个类想被用于for ... in循环，类似list或tuple那样，就必须实现一个__iter__()方法。
# 该方法返回一个迭代对象，然后，Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值，直到遇到StopIteration错误时退出循环。
# 斐波那契数列
class Fib():
    def __init__(self):
        self._a = 0
        self._b = 1

    def __iter__(self):
        return self

    def __next__(self):
        self._a, self._b = self._b, self._a + self._b
        if self._a > 20:
            raise StopIteration
        return self._a

    def __getitem__(self, n):
        if isinstance(n, int):
            a, b = 0, 1
            for x in range(n):
                a, b = b, a + b
            return a
        if isinstance(n, slice):
            start, stop = n.start, n.stop
            if start is None:
                start = 0
            L = []
            a, b = 0, 1
            for x in range(stop):
                if start <= x:
                    L.append(a)
                a, b = b, a + b
            return L

    # 当调用不存在的属性时
    # 注意，只有在没有找到属性的情况下，才调用__getattr__
    def __getattr__(self, attr):
        if attr == 'score':
            return 99
        elif attr == "age":
            # 也能返回一个函数
            return lambda x: x * x
        raise AttributeError("object 'Student' has no attribute %s " % attr)

    # 直接调用对象将调用此函数
    def __call__(self):
        print("I'am Fib()！")


# for i in Fib():
#    print(i)
print('#############定制类__getitem__，使类像list一样可以通过下标取元素#############')
f = Fib()
print(f[0])
print(f[1])
print(f[2])
print(f[3])
print(f[4])
print(f[5])
print(f[6])
print(f[100])
print('#############定制类__getitem__，的切片#############')
print(Fib()[0:5])
print(Fib()[:10])
print(Fib()[5:10])
print('#############定制类__delitem__，删除元素#############')
print('#############定制类__setitem__，赋值操作#############')
print(f.score)
print(f.age(25))
# print(f.assss)
print('#############链式调用#############')


class Chain(object):
    def __init__(self, path=''):
        self._path = path

    def __getattr__(self, path):
        print('__getattr__', 'self._path:', self._path, 'path:', path)
        return Chain('%s/%s' % (self._path, path))

    def __str__(self):
        print('__str__', self._path)
        return self._path

    __repr__ = __str__


print(Chain().user)
c = Chain()
print('#############链式调用过程#############')
print(c.user.music.list.file)
print('#############直接对实例进行调用__call__，将对象看成函数#############')
f()
print('#############通过callable()函数，我们就可以判断一个对象是否是“可调用”对象。#############')
print(callable(f))
print(callable(f()))
